package com.lbt.javaSE.gragh.impl;

import com.lbt.javaSE.gragh.Gragh;

import java.util.*;
import java.util.*;

@SuppressWarnings("unchecked")
public class GraghList<V,E> implements Gragh<V,E> {

    private Map<V,Vertex<V,E>> vertexMap=new HashMap<>();   //存储所有的节点信息
    private Set<Edge<V,E>> edges=new HashSet<>();       //存储所有的边

    public void print(){
        System.out.println("-----------顶点------------------");
        vertexMap.forEach((V v,Vertex<V,E> vertex)->{
            System.out.println(v);
            System.out.println("inEdge");
            System.out.println(vertex.inEdge.toString());
            System.out.println("outEdge");
            System.out.println(vertex.outEdge.toString());
        });
        System.out.println("---------边---------------");
        edges.forEach((Edge<V,E> edge)->{
            System.out.println( edge);
        });
    }
    private static class Vertex<V,E>{     //顶点
        V value;
        Set<Edge<V,E>> inEdge=new HashSet<>();
        Set<Edge<V,E>> outEdge=new HashSet<>();
        public Vertex(V value) {
            this.value = value;
        }

        @Override
        public boolean equals(Object o) {
           return Objects.equals(value,((Vertex<V,E>)o).value);
        }

        @Override
        public int hashCode() {
            return value== null? 0 : value.hashCode();
        }

        @Override
        public String toString() {
            String valueString=(value==null?"null":value.toString());
            return valueString;
        }
    }
    private static class Edge<V,E>{      //边
        Vertex<V,E> from;
        Vertex<V,E> to;
        E weight;
        public Edge(Vertex<V, E> vertexIN, Vertex<V, E> vertexTo) {
            this.from=vertexIN;
            this.to=vertexTo;
        }

        public Edge(Vertex<V, E> from, Vertex<V, E> to, E weight) {
            this.from = from;
            this.to = to;
            this.weight = weight;
        }

        @Override
        public boolean equals(Object o) {
            Edge<V,E> edge= (Edge<V, E>) o;
            return Objects.equals(from,edge.from)&&Objects.equals(to,edge.to);
        }

        @Override
        public int hashCode() {
            return from.hashCode()+31+to.hashCode();
        }

        @Override
        public String toString() {
            return "Edge{" +
                    "from=" + from +
                    ", to=" + to +
                    ", weight=" + weight +
                    '}';
        }
    }

    @Override
    public int VertexSize() {       //顶点个数
        return vertexMap.size();
    }

    @Override
    public int EdgeSize() {
        return edges.size();
    }

    @Override
    public void addVertex(V v) {    //添加顶点
        if(vertexMap.containsValue(v)) return ;
        vertexMap.put(v,new Vertex<>(v));

    }

    @Override           //删除顶点  还要删除边
    public boolean deleteVertex(V v) {
        Vertex<V, E> remove = vertexMap.remove(v);
        if(remove==null) return false;

        int size = remove.outEdge.size();
        int size1 = remove.inEdge.size();
        System.out.println("//////////////////////");
        System.out.println("----------------outEdge:_"+size+"___inEdge_:"+size1);

        for(Iterator<Edge<V, E>> iterator =remove.outEdge.iterator();iterator.hasNext();){
            Edge<V, E> edge = iterator.next();
            System.out.println(edge.toString());
            edge.to.inEdge.remove(edge);
            iterator.remove();
            edges.remove(edge);
        }
        for(Iterator<Edge<V, E>> iterator =remove.inEdge.iterator();iterator.hasNext();){
            Edge<V, E> edge = iterator.next();
            System.out.println(edge.toString());
            edge.from.outEdge.remove(edge);
            iterator.remove();
            edges.remove(edge);
        }
        return true;
    }

    @Override
    public void addEdge(V in, V to, E weight) {

        Vertex<V, E> vertexIN = vertexMap.get(in);
        if(vertexIN==null){
            vertexIN=new Vertex<>(in);
            vertexMap.put(in,new Vertex<>(in));
        }

        Vertex<V, E> vertexTo = vertexMap.get(to);
        if(vertexTo==null){
            vertexTo=new Vertex<>(to);
            vertexMap.put(to,new Vertex<>(to));
        }

        Edge<V,E> edge=new Edge<>(vertexIN,vertexTo);
        edge.weight=weight;
        if( vertexIN.outEdge.remove(edge)){
            vertexTo.inEdge.remove(edge);
            edges.remove(edge);
        }
        vertexMap.get(in).outEdge.add(edge);
        vertexMap.get(to).inEdge.add(edge);
//        boolean add = vertexIN.outEdge.add(edge);
//        System.out.println("add_:"+add);
        vertexTo.inEdge.add(edge);
        edges.add(edge);
    }

    @Override
    public void addEdge(V in, V to) {
        addEdge(in,to,null);
    }

    @Override
    public boolean deleteEdge(V in, V to) {
        Vertex<V, E> vertexIn = vertexMap.get(in);
        Vertex<V, E> vertexTo = vertexMap.get(to);
        Edge<V,E> edge=new Edge<>(vertexIn,vertexTo);
        if(edges.contains(edge)){
            vertexIn.outEdge.remove(edge);
            vertexTo.inEdge.remove(edge);
            return edges.remove(edge);
        }
        return false;
    }

    public void bfs(V v){
        Vertex<V,E> begin=new Vertex<>(v);
        if(!vertexMap.containsValue(begin)) return;
        Queue<Vertex<V,E>> vertexQueue=new LinkedList<>(); //将要遍历的顶点加入队列
        Set<Vertex<V,E>> visitedVertex=new HashSet<>();  //将便利过的顶点加入集合
        vertexQueue.offer(begin);   //将指定元素添加到此列表的末尾（最后一个元素）。
        visitedVertex.add(begin);  //遍历之后加入遍历过的集合之中
        int index=1;
        while (!vertexQueue.isEmpty()){
//            System.out.println("index_:"+index);
//            index++;
            Vertex<V, E> vertex = vertexQueue.poll(); //找到并移除此列表的头（第一个元素）。\
//            visitedVertex.add(vertex);  //遍历之后加入遍历过的集合之中
//            System.out.println(vertex.value.toString());        //打印
            System.out.println("out:::::"+vertex.outEdge.size());
            for(Edge<V,E> edge:vertex.outEdge){
                System.out.println("index2_:"+index);
                if(visitedVertex.contains(edge.to)) continue;
                visitedVertex.add(vertex);  //遍历之后加入遍历过的集合之中
                vertexQueue.offer(edge.to);
            }
        }
    }
    public void getOutEdges(V v){
        Vertex<V, E> vertex = vertexMap.get(v);
        Iterator<Edge<V, E>> iterator = vertex.outEdge.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next().toString());
        }
    }
}
